package com.senni;

import com.senni.annotation.FeignClient;
import com.senni.annotation.LocalClient;
import lombok.SneakyThrows;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

public class OpenFeignScanner extends ClassPathBeanDefinitionScanner {

    public OpenFeignScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }
    PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
    /**
     * 扫描所有需要被feign代理的字节码
     * */
    public List<Class> doScanAndNewProxy(String... basePackages) throws IOException, ClassNotFoundException {
        List<Class>  context=new ArrayList<>();
        int length = basePackages.length;
        for(int i=0;i<length;i++){
            String basePackage=basePackages[i];
            initProxyFeign(basePackage,context);
        }

        return context;
    }
    public Set<BeanDefinitionHolder> doScan(String... basePackages){
        return super.doScan(basePackages);
    }

    @SneakyThrows
    public Set<BeanDefinition> findCandidateComponents(String basePackages){
        LinkedHashSet candidates = new LinkedHashSet();
        String packageSearchPath = "classpath*:" + this.resolveBasePackage(basePackages) + "/**/*.class";
        Resource[] resources = pathMatchingResourcePatternResolver.getResources(packageSearchPath);
        for (Resource resource : resources) {
            MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
            if(!checkAnnotation(metadataReader, LocalClient.class)){
                continue;
            }
            ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
            sbd.setSource(resource);
            candidates.add(sbd);
        }
        return candidates;
    }
    private void initProxyFeign(String basePackage, List<Class> context) throws IOException, ClassNotFoundException {
        String packageSearchPath="classpath*:"+resolveBasePackage(basePackage)+"/**/*.class";
        Resource[] resources = pathMatchingResourcePatternResolver.getResources(packageSearchPath);
        for (int i = 0; i < resources.length; i++) {
            Resource resource = resources[i];
            MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
            if(!checkAnnotation(metadataReader, FeignClient.class)){
                continue;
            }
            String className = metadataReader.getClassMetadata().getClassName();
            Class<?> aClass = Class.forName(className);
            context.add(aClass);
        }
    }

    private  boolean checkAnnotation(MetadataReader reader,Class<? extends Annotation> annotation){
        MergedAnnotations annotations = reader.getAnnotationMetadata().getAnnotations();
        MergedAnnotation<? extends Annotation> mergedAnnotation = annotations.get(annotation);
        return mergedAnnotation.isPresent();
    }


}